package p.ithorns.sample.websocket.debugger;

import io.netty.channel.Channel;
import io.netty.handler.codec.http.HttpHeaderNames;
import io.netty.handler.codec.http.HttpHeaders;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.MultiValueMap;
import org.yeauty.annotation.*;
import org.yeauty.pojo.Session;
import p.ithorns.framework.common.utils.JsonUtil;
import p.ithorns.framework.common.utils.StringUtil;
import p.ithorns.sample.websocket.model.WsUpMsg;

import java.util.Arrays;
import java.util.Map;

/**
 * GateDebugWsEndpoint
 *
 * 直接可用的软件
 * https://linux.cn/article-9472-1.html
 *
 * @author Ht.L
 * @date 2023-06-19 10:22
 * @since 1.0.0
 */
@Slf4j
//@ServerEndpoint(path = "${app.websocket.path}", port = "${app.websocket.port}")
public class DebugWsEndpoint {

    private static final String CLIENT_ID = "CLIENT_ID";

    private static final String DEV_ID = "DEV_ID";


    @Autowired
    private DebugWsMsgHandler wsMsgHandler;


    @BeforeHandshake
    public void handshake(Session session, HttpHeaders headers,
                          @RequestParam MultiValueMap reqMap,
                          @PathVariable Map pathMap,
                          @RequestParam String req,
                          @PathVariable String arg) {
        String subProtocols = headers.get(HttpHeaderNames.SEC_WEBSOCKET_PROTOCOL);
        if (StringUtil.isBlank(subProtocols)) {
            log.warn("Authentication failed!");
            session.close();
        }

        // 参数需要有2个: 1-客户端ID, 2-基站ID
        String[] protocols = StringUtil.split(subProtocols, ",");
        if (protocols.length < 2) {
            log.warn("WebSocket参数缺失:{}", Arrays.toString(protocols));
            session.close();
            return;
        }

        session.setSubprotocols(subProtocols);
        session.setAttribute(CLIENT_ID, protocols[0]);
        session.setAttribute(DEV_ID, protocols[1]);
    }

    @OnOpen
    public void onOpen(Session session, HttpHeaders headers) {
        Channel channel = session.channel();
        log.info("WebSocket 打开连接：{}", channel);

        final String wsClientChId = getWsChId(session);

        // 注册客户端Channel
        DebugWsTcpSupervise.register(wsClientChId, channel);

        final String devId = session.getAttribute(DEV_ID);

        DebugTcpServer tcpServer = DebugTcpServer.getInstance();
        tcpServer.connect(() -> callback(devId, wsClientChId));

        // 发送一条消息
        // channel.writeAndFlush("Hello, " + wsClientChId);
        DebugWsTcpSupervise.sendToWs(getWsChId(session), "Hello, " + wsClientChId);
    }

    @OnMessage
    public void onMessage(Session session, String message) {
        log.info(message);

        // 解析和处理消息
        WsUpMsg<String> msg = JsonUtil.fromJson(message, WsUpMsg.class);
        if (null != msg) {
            msg.setClientId(getWsChId(session));
            wsMsgHandler.handle(msg);

            String data = msg.getData();
            String tcpChId = getTcpChId(session);
            if (null != tcpChId) {
                DebugWsTcpSupervise.sendToTcp(tcpChId, data);
            }
        }
    }

    @OnClose
    public void onClose(Session session) {
        Channel channel = session.channel();
        log.info("Session closed: {}", channel);
        DebugWsTcpSupervise.removeChannel(channel);

        // 检查有没有TCP连接，在最后一个事件时关闭TCP服务
        if (DebugWsTcpSupervise.ifNoTcpConnect()) {
            DebugTcpServer.getInstance().stop();
        }
    }

    @OnError
    public void onError(Session session, Throwable throwable) {
        log.error("WebSocket error.", throwable);
        session.close();
    }

    /**
     * WS调试开启后下发MQTT指令给基站
     */
    private void callback(String devId, String clientId) {
        log.info("向设备下发调试指令：{} -> {}", devId, clientId);
    }

    private String getWsChId(Session session) {
        String wsClientId = getWsClientId(session);
        return wsClientId + ":" + session.id().asShortText();
    }

    private String getTcpChId(Session session ) {
        String wsClientId = getWsChId(session);
        String tcpChId = DebugWsTcpSupervise.getTcpId(wsClientId);
        if (null == tcpChId) {
            return null;
        }
        return wsClientId + ":" + tcpChId;
    }

    private String getWsClientId(Session session) {
        final String devId = session.getAttribute(DEV_ID);
        final String client = session.getAttribute(CLIENT_ID);
        return client + ":" + devId;
    }

    private String getAttribute(Session session, String key) {
        return session.getAttribute(key);
    }

}